//TODO: more cases for  Converting  Idiom
//
//OK impl From<B>   B.into()
// impl TryFrom<B> =>  B.try_into()
//
//OK impl FromStr   => ::<Self>
//OK impl Display =>  Self.to_string
//
//OK impl AsRef<Target>, 
//OK impl AsMut<Target>

use std::ops::Deref;
use std::ops::DerefMut;
use std::fmt;
use std::str::FromStr;
use std::convert;

#[derive(Default)]
struct MyString (String);

impl Deref for MyString {
    type Target = str;

    fn deref(&self) -> &str {
        println!("deref");
        &(self.0)
    }
}
impl DerefMut for MyString {
    fn deref_mut(&mut self) -> &mut str {
        println!("deref_mut");
        &mut self.0
    }
}

impl From<&str> for MyString {
    fn from(s: &str) -> Self {
        Self(s.to_owned())
    }
}

impl From<&mut str> for MyString {
    fn from(s: &mut str) -> Self {
        Self(s.to_owned())
    }
}



impl FromStr for MyString {
    type Err = convert::Infallible;
    fn from_str(s: & str) -> Result<Self, <Self as FromStr>::Err> {
        Ok(Self(s.to_owned()))
    }
}
impl fmt::Display for MyString {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "{}", self.0)
    }
}

impl AsRef<str> for MyString {
    fn as_ref(&self) -> &str {
        &self.0  //no-call the Deref::deref 
    }
}
impl AsMut<str> for MyString {
    fn as_mut(&mut self) -> &mut str {
       &mut self.0 //no-call the DerefMut::deref_mut
    }
}


#[cfg(test)]
mod tests {
    
    use super::*;

    // &str <= &String, <= MyString
    //bad fn three_vowels(word: &String) -> bool {
    fn three_vowels(word: &str) -> bool {
        let mut vowel_count = 0;
        for c in word.chars() {
            match c {
                'a' | 'e' | 'i' | 'o' | 'u' => {
                    vowel_count += 1;
                    if vowel_count >= 3 {
                        return true;
                    }
                }
                _ => vowel_count = 0,
            }
        }
        false
    }
    #[test]
    fn use_coercion() {
        let ferris = "Ferris".to_string(); //case1.
        println!("{}:{}", ferris, three_vowels(&ferris));

        //case 2
        println!("ferris: {}", three_vowels("ferris"));

        //case 3
        let my_ferris = MyString(ferris);
        println!("ferris: {}", three_vowels(&my_ferris));

        //case 4
        let sentence = "Once upon a time, there was a friendly curious crab named Ferris".to_string();
        for word in sentence.split(' ') {
            if three_vowels(word) {
                println!("{word} has three_vowels consecutive vowels!");
            }
        }
    }

    #[test]
    //care performance use Pre-alloc String with push operation
    fn use_format(){
        let world = "world";
        assert!("hello world" == format!("hello {world}"))
    }


    fn change_mut_str(s : &mut str) {
        if s.len() > 0 {
            s.make_ascii_lowercase()
        }
    }

    #[test]
    fn constructor(){
        let _s = MyString::default();

        let mut _s = MyString::default();

        let _s = MyString::from("hello");

        change_mut_str(&mut "hello".to_owned());

        let mut s: String = "hello".to_owned();
        change_mut_str(&mut s); //call String::DerefMut

        let mut my_s = MyString::from(s.as_mut());
        // call MyString::DerefMut  
        change_mut_str(&mut my_s);

        // call  AsMut<str>
        change_mut_str(my_s.as_mut());
    }


    #[test]
    fn as_ref_as_mut(){
        let s = MyString::default();
        s.as_ref();

        let mut s = MyString::default();
        s.as_mut();

        let s: MyString =  "hello".into();
        println!("MyString with format!: {}", format!(" haha: {}", s));
        println!("mystring.to_string: {}", s.to_string());

        let s = "world".parse::<MyString>().unwrap();
        println!("str.parse::<MyString>().unwrap() -> {s}")
    }
    

    #[derive(Debug)]
    enum MyEnum {
        A {name : String, x : u8},
        B {name: String},
    }
    use std::mem;
    fn a_to_b(e: &mut MyEnum){
        if let MyEnum::A { name, x: 0} = e {
            *e = MyEnum::B {
                name: mem::take(name),
            }
        }
    }
    #[test]
    fn change_enum_in_place(){
        let mut a = MyEnum::A{ name:"hello".to_owned(), x: 0};
        println!("MyEnum:{:?}", a);
        if let MyEnum::A { name, x: 0} =  &mut a {
            a = MyEnum::B {name: mem::take(name)};
        }
        println!("MyEnum:{:?}", a);

        a_to_b(&mut a);
        println!("MyEnum:{:?}", a);

        let b = MyEnum::B {name: "plan b".to_owned()};
        if let MyEnum::B { name } = b {
           println!("MyEnum:{:?}", name);
        }
    }

    #[derive(Debug)]
    struct MyStruct {
        name : String,
    }
    #[test]
    fn change_strut_in_place(){
        let mut s = MyStruct { name : "hello".to_owned()};
        println!("MyStruct:{:?}", s);
       
        mem::take(&mut s.name);
        println!("MyStruct:{:?}", s);
        
    }



    use std::io;
    use std::fs;
    #[test]
    fn create_trait_base() -> io::Result<()> {
        let arg = "-";
        let _readable: &dyn io::Read = if arg == "-" {
            &mut io::stdin()
        } else {
            &mut fs::File::open(arg)?
        };
        Ok(())
    }

    


        
}

